﻿using MediatR.Pipeline;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;
using Autofac;
using System.Reflection;

using System.Threading;
using Autofac.Core;
using Autofac.Extensions.DependencyInjection;

namespace MediatR
{
    public class MediatServiceProvider
    {
        IMediator _mediator = null;

        PublisherX _publisherX = null;
        Publisher _publisher = null;

        ContainerBuilder _containerBuilder = null;

        IContainer _container = null;

        AutofacServiceProvider _serviceProvider = null;


        private static MediatServiceProvider _instance = null;

        public MediatServiceProvider()
        {
            ServiceCollection services = new ServiceCollection();

            _containerBuilder = new ContainerBuilder();

            _containerBuilder.Populate(services);

            Init();
        }


        public static MediatServiceProvider Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new MediatServiceProvider();
                }
                return _instance;
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        void Init()
        {
            _containerBuilder.RegisterType<Publisher>().SingleInstance();
            _containerBuilder.RegisterType<PublisherX>().SingleInstance();

            _containerBuilder.RegisterAssemblyTypes(typeof(IMediator).GetTypeInfo().Assembly).AsImplementedInterfaces();
        }

        /// <summary>
        /// 发送，一对一
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task Send(object notification, CancellationToken cancellationToken = default)
        {
            return _mediator.Send(notification, cancellationToken);
        }

        /// <summary>
        /// 发布，一对多(不带路由)
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public Task Publish(object notification, CancellationToken cancellationToken = default)
        {
            return _publisher.Publish(notification, cancellationToken);
        }

        /// <summary>
        /// 发布，一对多(带路由)
        /// </summary>
        /// <param name="notification"></param>
        /// <param name="cancellationToken"></param>
        public Task PublishRoute(object notification, CancellationToken cancellationToken = default)
        {
           return _publisherX.Publish(notification, cancellationToken);
        }

        public Task PublishRoute<IRouteNotification>(IRouteNotification notification, CancellationToken cancellationToken = default)
        {
            if (notification == null)
            {
                throw new ArgumentNullException(nameof(notification));
            }

            return _publisherX.Publish(notification, cancellationToken);
        }

        public void RegisterAssemblyTypes(Assembly[] assembly)
        {

            var mediatrOpenTypes = new[]
            {
                typeof(IRequestHandler<,>),
                typeof(IRequestExceptionHandler<,,>),
                typeof(IRequestExceptionAction<,>),
                typeof(INotificationHandler<>),
                typeof(IStreamRequestHandler<,>),
                typeof(IRouteNotificationHandler<>)
            };

            foreach (var item in assembly)
            {
                foreach (var mediatrOpenType in mediatrOpenTypes)
                {
                    _containerBuilder
                        .RegisterAssemblyTypes(item)
                        .AsClosedTypesOf(mediatrOpenType)
                        .AsImplementedInterfaces();
                }
            }
        }

        public void Build()
        {
            _container = _containerBuilder.Build();
            _serviceProvider = new AutofacServiceProvider(_container);

            _publisherX = _serviceProvider.GetRequiredService<PublisherX>();
            _publisher = _serviceProvider.GetRequiredService<Publisher>();
            _mediator = _serviceProvider.GetRequiredService<IMediator>();
        }
    }
}
